跳到主要内容

Go 读取模板文件之 template 包

Golang 官方提供了 template 包用来方便用户动态模板文件

下文因为转码的问题, {{ 都改成了 {/{

Go语言模板引擎的使用可以分为三部分:定义模板文件、解析模板文件和模板渲染。

按照相应的语法编写模板文件。

<html>

<head>
<title>模板文件</title>
</head>

<body>
hello {\{ . }}
</body>

</html>

Go语言内置了文本模板引擎 text/template 和用于 HTML 文档的 html/template。它们的作用机制可以简单归纳如下:

  • 模板文件通常定义为 .tmpl.tpl 为后缀(也可以使用其他的后缀),必须使用 UTF8 编码。
  • 模板文件中使用 {\{\}} 包裹和标识需要传入的数据。
  • 传给模板的数据可以通过点号 . 来访问,如果数据是复杂类型的数据,可以通过 {\{ .FieldName }} 来访问它的字段。
  • {\{\}} 包裹的内容外,其他内容均不做修改原样输出。

提供的解析方法

系统定义了一些模板解析方法,获得模板对象

// 创建模板对象,并为其添加一个模板名称
func New(name string) *Template {}

// 解析字符串,比如template.New("name").Parse(src string) 创建模板对象,并完成模板解析。
func (t *Template) Parse(src string) (*Template, error) {}

// 解析模板文件得到模板对象,可以同时解析多个文件
func ParseFiles(filenames ...string) (*Template, error) {}

// 批量解析文件,比如解析当前目录下有以h开头的模板文件:template.ParseGlob("h*")
func ParseGlob(pattern string) (*Template, error) {}

解析模板的时候,有几个实用的方法

// 模板包里面有一个函数Must,它的作用是检测模板是否正确。
// 例如大括号是否匹配,注释是否正确的关闭,变量是否正确的书写
func Must(t *Template, err error) *Template

// Funcs方法向模板t的函数字典里加入参数funcMap内的键值对。
// 如果funcMap某个键值对的值不是函数类型或者返回值不符合要求会panic。
// 但是,可以对t函数列表的成员进行重写。方法返回t以便进行链式调用
func (t *Template) Funcs(funcMapFuncMap) *Template

模板渲染,模板渲染就是将后台的数据替换模板文件中的特定占位符,这里的特定字符是模板文件中的 {\{ . }}。系统定义了两个渲染方法:

func (t *Template) Execute(wr io.Writer, data interface{}) error {}
func (t *Template) ExecuteTemplate(wr io.Writer, name string, data interface{}) error {}

Execute 用来渲染单个模板,如果是用 ParseFiles,ParseGlob 一次性加载了多个模板,就需要用 ExecuteTemplate 选择模板来解析。

模板的语法

在 golang 渲染 template 的时候,可以接受一个 interface{} 类型的变量

有两个常用的传入参数的类型:

  • 在模板内可以读取该 struct 域的内容来进行渲染
  • map[string]interface{},在模板内可以使用 key 来进行渲染。

模板内内嵌的语法支持,全部需要加 {\{}} 来标记。

在模板文件内,. 代表了当前变量,即在非循环体内,. 就代表了传入的那个变量。假设我们定义了一个结构体:

type Article struct {
ArticleId int
ArticleContent string
}

则可以在模板中

<p>{\{.ArticleContent}}<span>{\{.ArticleId}}</span></p>

同时模板文件也有语法,例如在模板中定义一个变量

{\{$article := .ArticleContent}}

这样就可以把 ArticleContent 字段赋值给 article 变量,这样我们只要使用 {\{$article}} 则可以获取到这个变量的内容。

循环

golang 的 template 支持 range 循环来遍历 map、slice 内的内容,语法为:

{\{range $i, $v := .slice}}
{\{end}}

在这个 range 循环内,我们可以通过 i v 来访问遍历的值

还有一种遍历方式为:

{\{range .slice}}
{\{end}}

这种方式无法访问到 index 或者 key 的值,需要通过 . 来访问对应的 value

{\{range .slice}}
{\{.field}}
{\{end}}

这里使用了 . 来访问遍历的值,那么我们想要在其中访问外部的变量怎么办?(比如渲染模板传入的变量),在这里,我们需要使用 $. 来访问外部的变量

{\{range .slice}}
{\{$.ArticleContent}}
{\{end}}

使用例:

<html>

<head>
<title>模板文件</title>
</head>

<body>
These are error messages:
{\{range $i, $v := .}}
<li> {\{.}}{\{end}}
</body>

</html>

在 Golang 中

import (
_ "embed"
"html/template"
"os"
)

//go:embed static/index.tpl
var content string

func main() {
errors := []string{
"这是错误 1",
"这是错误 2",
"这是错误 3",
"这是错误 4",
"这是错误 5",
"这是错误 6",
}

tmpl := template.New("temp1")
tmpl.Parse(content)
tmpl.Execute(os.Stdout, errors)
}

输出:

<html>

<head>
<title>模板文件</title>
</head>

<body>
These are error messages:

<li> 这是错误 1
<li> 这是错误 2
<li> 这是错误 3
<li> 这是错误 4
<li> 这是错误 5
<li> 这是错误 6
</body>

</html>

调用方法

除了定义变量,在模板文件内,调用方法也非常的简单:

template 包创建新的模板的时候,支持 .Funcs 方法来将自定义的函数集合导入到该模板中,后续通过该模板渲染的文件均支持直接调用这些函数。

该函数集合的定义为:

type FuncMap map[string]interface{}

key 为方法的名字,value 则为函数。这里函数的参数个数没有限制,但是对于返回值有所限制。有两种选择,一种是只有一个返回值,还有一种是有两个返回值,但是第二个返回值必须是 error 类型的。这两种函数的区别是第二个函数在模板中被调用的时候,假设模板函数的第二个参数的返回不为空,则该渲染步骤将会被打断并报错。

在模板文件内,调用方法也非常的简单:

{\{funcname .arg1 .arg2}}

使用例

定义了一个函数

func add(left int, right int) int

则在模板文件内,通过调用

{\{add 1 2}}

就可以获得

3

更多细节参考 golang 模板(template)的常用基本语法

使用例

import (
"fmt"
"os"
"text/template"
)

func main() {

type person struct {
Id int
Name string
Country string
}

user := person{Id: 1001, Name: "jim", Country: "China"}

fmt.Println("user = ", user)

tmpl := template.New("tmpl1")
tmpl.Parse("Hello {\{.Name}} Welcome to go programming...\n")
tmpl.Execute(os.Stdout, user)
}

输出:

user =  {1001 jim China}
Hello jim Welcome to go programming...

读取到 String 里面

t := template.New("action")

var err error
t, err = t.ParseFiles("path/to/action.html")
if err != nil {
return err
}

key := "some strings"

data := struct{
Key string
}{
Key: key
}

var tpl bytes.Buffer
if err := t.Execute(&tpl, data); err != nil {
return err
}

result := tpl.String()

References

Go总结(五)| 强大的HTML模板解析 golang 模板(template)的常用基本语法